#ifndef CONFIGMANAGER_H
#define CONFIGMANAGER_H

#include <yaml-cpp/yaml.h>
#include <string>
#include <mutex>
#include <QVariantMap>
#include "logger.h"
#include <QVariant>

#define ParamValue ConfigManager::getInstance()

namespace YAML
{
template <>
struct convert<QVariant>
{
    static Node encode(const QVariant &rhs)
    {
        Node node;
        switch (rhs.type())
        {
        case QVariant::String:
            node = rhs.toString().toStdString();
            break;
        case QVariant::Int:
            node = rhs.toInt();
            break;
        case QVariant::UInt:
            node = rhs.toUInt();
            break;
        case QVariant::Double:
            node = rhs.toDouble();
            break;
        case QVariant::Bool:
            node = rhs.toBool();
            break;
        case QVariant::List:
        {
            QVariantList list = rhs.toList();
            for (const QVariant &item : list)
            {
                node.push_back(encode(item)); // 递归调用encode处理列表项
            }
            break;
        }
        case QVariant::Map:
        {
            QVariantMap map = rhs.toMap();
            for (auto it = map.cbegin(); it != map.cend(); ++it)
            {
                node[it.key().toStdString()] = encode(it.value()); // 递归调用encode处理映射项
            }
            break;
        }
        default:
            throw std::runtime_error("Unsupported QVariant type for YAML serialization");
        }
        return node;
    }

    static bool decode(const Node &node, QVariant &rhs)
    {
        if (node.IsScalar())
        {
            rhs = QString::fromStdString(node.Scalar());
            return true;
        }
        else if (node.IsSequence())
        {
            QVariantList list;
            for (const auto &it : node)
            {
                QVariant value;
                if (decode(it, value)) // 递归调用decode处理序列项
                {
                    list.push_back(value);
                }
            }
            rhs = list;
            return true;
        }
        else if (node.IsMap())
        {
            QVariantMap map;
            for (auto it = node.begin(); it != node.end(); ++it)
            {
                QVariant value;
                if (decode(it->second, value)) // 递归调用decode处理映射项
                {
                    map[QString::fromStdString(it->first.Scalar())] = value;
                }
            }
            rhs = map;
            return true;
        }
        return false;
    }
};
template <>
struct convert<QString>
{
    static Node encode(const QString &rhs)
    {
        return Node(rhs.toStdString());
    }

    static bool decode(const Node &node, QString &rhs)
    {
        if (!node.IsScalar())
            return false;
        rhs = QString::fromStdString(node.Scalar());
        return true;
    }
};
template <>
struct convert<QList<QVariant>>
{
    static Node encode(const QList<QVariant> &rhs)
    {
        Node node(NodeType::Sequence);
        for (const auto &item : rhs)
        {
            node.push_back(convert<QVariant>::encode(item));
        }
        return node;
    }

    static bool decode(const Node &node, QList<QVariant> &rhs)
    {
        if (!node.IsSequence())
        {
            return false;
        }
        for (const auto &item : node)
        {
            QVariant value;
            if (convert<QVariant>::decode(item, value))
            {
                rhs.push_back(value);
            }
        }
        return true;
    }
};
}

class ConfigManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString configfileName READ ccnfigfileName NOTIFY fileNameChanged)
    Q_PROPERTY(QVariantMap valueTable READ valueTable  NOTIFY valueTableChanged)
public:
    const QString ConfigPath = "master/config/";
    QString defaultPath = "default.yaml";
    QString filePath= ConfigPath + "lastPath.txt";
    static ConfigManager &getInstance();
    void loadConfigTable(const std::string &configTableFile);
    Q_INVOKABLE void loadOrCreateValueTable(const std::string &valueTableFile);
    bool saveValueTable(const std::string &valueTableFile);

    QVariant getParameter(const QString &section, const QString &key) const
    {
        QString name(section + "/" + key);
        auto it = valueTable_.find(name);
        if (it != valueTable_.end()) {
            return it.value();
        } else {
            qCritical() << "Parameter not found [" << section << "] [" << key << "]";
            throw std::runtime_error("Parameter not found");
        }
    }
    template <typename T>
    T getParameter(const QString &section, const QString &key) const;

    template <typename T>
    void setParameter(const QString &section, const QString &key, const T &value);

    QVariantMap getAllParameters() const;
    QVariantMap getAllParametersByCategory(std::string category) const;
    QVariantMap getConfig(const std::string &section, const std::string &parameterName);
    QString ccnfigfileName() const {return configfileName_;};
    bool checkAndCreateFile(const QString &filePath) ;
    QVariantMap valueTable() const {return valueTable_;};
    static const char * configFileName();
signals:
    void configDataChanged(const QString& section, const QString& changedKey);
    void valueTableLoad();
    void fileNameChanged();
    void valueTableChanged();

public slots:
    void configParamSave();

private:
    ConfigManager(QObject *parent = nullptr);
    ~ConfigManager();
    ConfigManager(const ConfigManager &) = delete;
    ConfigManager &operator=(const ConfigManager &) = delete;

    void initializeValuesFromConfig();
    bool validateValue(const YAML::Node &paramConfig, const YAML::Node &value);
    QString configfileName_;

    YAML::Node configTable_;
    QVariantMap valueTable_;
    mutable std::mutex mutex_;
    bool validateType(const YAML::Node &typeNode, const YAML::Node &value);
    void setLastValueTablePath(const QString &path);
    QString getLastValueTablePath();
    QVariant parseValue(const YAML::Node &node) const;
    YAML::Node convertToYamlNode(const QVariant &value);
};

template<typename T>
T ConfigManager::getParameter(const QString &section, const QString &key) const {
    //std::lock_guard<std::mutex> lock(mutex_);
    QString name(section + "/" + key);
    auto it = valueTable_.find(name);
    if (it != valueTable_.end()) {
        return it.value().value<T>();
    } else {
        qCritical() << "Parameter not found [" << section << "] [" << key << "]";
        throw std::runtime_error("Parameter not found");
    }
}

template<typename T>
void ConfigManager::setParameter(const QString &section, const QString &key, const T &value) {
    std::lock_guard<std::mutex> lock(mutex_);
    QString name(section + "/" + key);
    auto it = valueTable_.find(name);
    if (it != valueTable_.end()) {
        it.value() = QVariant::fromValue(value);
    } else {
        qCritical() << "Parameter not found [" << section << "] [" << key << "]";
        throw std::runtime_error("Parameter not found in configuration schema");
    }
}

// template <typename T>
// T ConfigManager::getParameter(const QString &section, const QString &key) const {
//     // std::lock_guard<std::mutex> lock(getmutex_);
//     QVariantMap sectionMap = valueTable_.value(section).toMap();
//     LogDebug << "Parameter get [" << section << "] [" << key << "]: " << sectionMap.value(key).value<QString>();
//     if (sectionMap.contains(key)) {
//         return sectionMap.value(key).value<T>();
//     } else {
//         LogError << "Parameter not found [" << section << "] [" << key << "]";
//         throw std::runtime_error("Parameter not found");
//     }
// }

// template <typename T>
// void ConfigManager::setParameter(const QString &section, const QString &key, const T &value) {
//     std::lock_guard<std::mutex> lock(mutex_);
//     QVariant  value_ = QVariant::fromValue(value);
//     // LogError << "Attempting to setParameter  [" << section << "] [" << key << "]:" << value_.toString();
//     if (configTable_[section] && configTable_[section][key]) {
//         try {
//             QVariantMap sectionMap = valueTable_.value(section).toMap();
//             sectionMap[key] = value_;
//             valueTable_[section] = sectionMap;
//             //emit valueTableChanged();
//         } catch (const std::exception &e) {
//             LogError << "Failed to set value: " << e.what();
//         }
//     } else {
//         LogError << "Parameter not found [" << section << "] [" << key << "]";
//         throw std::runtime_error("Parameter not found in configuration table");
//     }
// }
int testParametertable();
#endif // CONFIGMANAGER_H
